﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Random = UnityEngine.Random;

public class EnemyCtrl : BaseMono, IOnExplode
{
	public Action OnReachTargetPos;
	public event Action<EnemyCtrl> OnDie;

	public bool IsDead = false;
	public float StopDis = 0.1f;
	public float SeekInterval = 10;

	public Image Img;
	public PathSeeker Seeker;
	public Rigidbody2D Rigidbody2D;
	public Animator Animator;

	public Vector2 newPos;
	public Vector3 TargetPos;

	private Transform MyTrans;

	public EnemyData Data;

	List<Vector3> nodeList = new List<Vector3>();

	public override void onAwake()
	{
		MyTrans = transform;

		Img = GetComponent<Image>();
		Rigidbody2D = gameObject.TryGetComponent<Rigidbody2D>();
		Animator = gameObject.GetComponent<Animator>();
		Seeker = gameObject.TryGetComponent<PathSeeker>();
	}

	public void Init(EnemyInfo info)
	{
		Data = new EnemyData(info);

		Born();
	}

	public void BindEvent()
	{
		AStarGridMgr.grid.OnGridChange += OnPathChange;
		Seeker.OnFindPath += SetPath;
		Seeker.OnFindPath += DrawPath;
	}

	public void ClearEvent()
	{
		AStarGridMgr.grid.OnGridChange -= OnPathChange;
		Seeker.OnFindPath -= SetPath;
		Seeker.OnFindPath -= DrawPath;
	}

	private void OnPathChange()
	{
		Seeker.SetPosition(MyTrans.position, TargetPos);
	}

	public override void onStart()
	{
		StartCoroutine(SetNewTargetByTime(SeekInterval));
	}

	public override void onUpdate()
	{
		if (IsDead)
		{
			return;
		}

		UpdateNode();
	}

	public override void onFixedUpdate()
	{
		if (IsDead)
		{
			return;
		}
		Move();
	}

	public void Born()
	{
		InitData(Data.Info.AILevel);
		IsDead = false;
		BindEvent();
		base.Init();
	}

	public void InitData(AILevel aiLevel)
	{
		switch (aiLevel)
		{
			case AILevel.Easy:
				Data.MoveSpeed = 1;
				Data.detectRadius = 8;
				Img.color = Color.white;
				break;
			case AILevel.Normal:
				Data.MoveSpeed = 1.5f;
				Data.detectRadius = 6;
				Img.color = new Color(1,1,0,1);
				break;
			case AILevel.Hard:
				Data.MoveSpeed = 2f;
				Data.detectRadius = 3;
				Img.color = new Color(1, 0, 0, 1);
				break;
		}
	}

	public void Move()
	{
		Vector2 vec = (newPos - Rigidbody2D.position).normalized;
		Vector2 pos = vec * Data.MoveSpeed * Time.deltaTime;

		float x = vec.x;
		float y = vec.y;
		if (Mathf.Abs(x) > Mathf.Abs(y))
		{
			if (Vector2.Dot(vec, Vector2.left) > 0)
			{
				Animator.SetTrigger("MoveLeft");
			}
			else
			{
				Animator.SetTrigger("MoveRight");
			}
		}
		else
		{
			if (Vector2.Dot(vec, Vector2.up) > 0) {
				Animator.SetTrigger("MoveUp");
			} else {
				Animator.SetTrigger("MoveDown");
			}
		}

		Rigidbody2D.MovePosition(Rigidbody2D.position + pos);
	}

	public void OnExplode() {
		Die();
	}

	public void Die() {
		Clear();
		if (OnDie != null)
		{
			OnDie(this);
		}

		Animator.SetTrigger("Dead");
	}

	public void Reset()
	{
		IsDead = true;
		nodeList.Clear();
		ClearEvent();
	}

	public void Clear()
	{
		Reset();
	}

	private void SetPath(List<Vector3> posList)
	{
		nodeList = posList;
		if (nodeList.Count <= 0)
		{
			newPos = new Vector2(Rigidbody2D.position.x, Rigidbody2D.position.y);
		}
	}

	private AStarNode SeekNode;
	private void UpdateNode()
	{
		int length = nodeList.Count;
		if (length > 0)
		{
			newPos = nodeList[length - 1];
			if (Vector3.Distance(newPos, Rigidbody2D.position) < StopDis)
			{
				nodeList.RemoveAt(length - 1);
			}
		}
		else
		{
			GetNextPos();
			if (OnReachTargetPos != null)
			{
				OnReachTargetPos();
			}
		}
	}

	private IEnumerator SetNewTargetByTime(float time)
	{
		while (true)
		{
			GetNextPos();

			yield return new WaitForSeconds(time);
		}
	}

	private void GetNextPos()
	{
		AStarNode node = GetRandomTarget(MainGame.Player.MyTrans.position,
				Random.Range(0, Mathf.Min(Data.detectRadius, MainGame.Ins.Row, MainGame.Ins.Col)));
		if (node != null) {
			TargetPos = node.Position;
		}
		Seeker.SetPosition(MyTrans.position, TargetPos);
	}

	private AStarNode GetRandomTarget(Vector3 pos, int radius)
	{
		AStarNode node = AStarGridMgr.grid.GetNodeByWorldPos(pos);

		List<IntVec2> dirList = new List<IntVec2>();
		dirList.Add(IntVec2.up);
		dirList.Add(IntVec2.down);
		dirList.Add(IntVec2.left);
		dirList.Add(IntVec2.right);

		do
		{
			int random = Random.Range(0, dirList.Count);
			IntVec2 index = node.Index + dirList[random] * radius;
			dirList.RemoveAt(random);
			if (AStarGridMgr.grid.WithInBorder(index))
			{
				return AStarGridMgr.grid.GetNode(index);
			}
		} while (dirList.Count > 0);

		MyLog.LogWarning("Not Find Random Node");
		return null;
	}

	/// <summary>
	/// 画出路径
	/// </summary>
	/// <param name="node"></param>
	public void DrawPath(List<Vector3> posList) {
		for (int i = 1, length = posList.Count; i < length; i++) {
			Debug.DrawLine(posList[i - 1], posList[i], Color.green, 1);
		}
	}
}
